﻿using System;
using System.Collections.Generic;
using System.Linq;
using COFE.Core;
using COFE.Core.Filter;
using COFE.Core.Profile;
using NUnit.Framework;

namespace COFE.Data
{
    public class DBCustomEntryList : EntryListBase, ICustomEntryList
    {
        #region Constructor

        public DBCustomEntryList(COFEDB2 contex, COFE.Data.CustomEntryList customList)
            : base(customList.EntryListId, customList.Name, null)
        {            
            Owner = customList.OwnerId;
        }


        #endregion

        #region Methods


        public void InsertRange(int index, IEnumerable<IFileSystemInfo> entries)
        {
            var etor = entries.GetEnumerator();
            List<Guid> entryToRemove = new List<Guid>(); //Remove it so it can be reposition.
            List<Entry> entryToAdd = new List<Entry>();

            COFEDBShared.DBOperations.UpdateDatabase((context) =>
                {
                    var el = getEntryList(context);
                    if (el != null)
                    {
                        el.Contents.Load();

                        while (etor.MoveNext()) //Iterate entries.
                        {
                            //Find the entry in dabase
                            var dbEntry = COFEDBShared.DBEntryManager.LookupEntry(context, etor.Current.GetId());
                            //If found in entry list.
                            if (!el.Contents.Any((e) => e.EntryId == etor.Current.GetId()))
                            {
                                //If the entry not in database.
                                if (dbEntry == null)
                                {
                                    //Create it.
                                    COFEDBShared.DBEntryManager.UpdateEntry((etor.Current as IInternalFileSystemInfoExA).PrimaryPropertyProvider);
                                    dbEntry = COFEDBShared.DBEntryManager.LookupEntry(context, etor.Current.GetId());
                                    Assert.IsNotNull(dbEntry);
                                }
                            }
                            else
                            {
                                //Remove it first.
                                entryToRemove.Add(etor.Current.GetId());
                            }

                            //Add to database (entry removed if it's in database).
                            entryToAdd.Add(dbEntry);
                        }
                    }
                    else
                        throw new Exception("Cannot find the custom entry list.");
                });


            //Remove duplicated entries.
            if (entryToRemove.Count > 0)
                Delete(new IEntryFilter[] { new GuidEntryFilter(entryToRemove.ToArray()) });

            COFEDBShared.DBOperations.UpdateDatabase(
                (context) => getEntryList(context),
                (context, el) =>
                {
                    el.Contents.Load();
                    el.InsertContent(context, index, entryToAdd.ToArray());
                    //foreach (var dbEntry in entryToAdd)
                    //    el.InsertContent(context, index++, dbEntry);

                    el.LastUpdateTime = DateTime.UtcNow;
                    context.SaveChanges();
                });

        }


        public void Delete(IEntryFilter[] matchFilter)
        {

            COFEDBShared.DBOperations.UpdateDatabase(
               (context) => getEntryList(context),
               (context, el) =>
               {
                   if (el == null)
                       throw new KeyNotFoundException("Custom entry list is not found.");

                   return (from e in Entries
                           where matchFilter.MatchEntry(e as IInternalFileSystemInfoExA)
                           select
                               COFEDBShared.DBEntryManager.LookupEntry(context, e.GetId())).ToArray();
               },
               (context, el, entryToDel) =>
               {
                   foreach (var dbEntry in entryToDel)
                       el.RemoveContent(context, dbEntry);
                   el.LastUpdateTime = DateTime.UtcNow;

                   context.SaveChanges();
               });
        }

        private COFE.Data.CustomEntryList getEntryList(COFEDB2 context)
        {
            return context                
                .EntryLists.FirstOrDefault(el => el.EntryListId == Id)
                            as COFE.Data.CustomEntryList;
        }

        #endregion

        #region Data

        #endregion

        #region Public Properties
        
        public string Owner { get; protected set; }

        public override IEnumerable<IFileSystemInfo> Entries
        {
            get
            {
                return COFEDBShared.DBOperations.ReadDatabase((context) =>
                    {
                        var el = getEntryList(context);
                        el.Contents.Load();
                        return (from e in el.Contents.OrderBy(e => e.Position)
                                select DBEntryConstructor.CreateEntry(e.GetEntry(context),
                                EntryConstructionFlags.Default)).ToList();
                    });

            }
        }
        
        #endregion
    }
}
